package com.wjh.config;

import java.util.ArrayList;
import java.util.List;

import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.DefaultConnectionKeepAliveStrategy;
import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.config.Registry;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.http.message.BasicHeader;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import lombok.extern.slf4j.Slf4j;

/**
 * @author wenjianhai
 * @date 2023/5/31
 * @since JDK 1.8
 */
@Slf4j
@Configuration
public class RestTemplateConfig {
	@Value("${http.maxTotal}")
	private Integer maxTotal;

	@Value("${http.defaultMaxPerRoute}")
	private Integer defaultMaxPerRoute;

	@Value("${http.connectTimeout}")
	private Integer connectTimeout;

	@Value("${http.connectionRequestTimeout}")
	private Integer connectionRequestTimeout;

	@Value("${http.socketTimeout}")
	private Integer socketTimeout;

	@Value("${http.staleConnectionCheckEnabled}")
	private boolean staleConnectionCheckEnabled;

	@Value("${http.validateAfterInactivity}")
	private Integer validateAfterInactivity;

	@Bean
	public RestTemplate restTemplate() {
		log.info("初始化RestTemplate-开始");
		return new RestTemplate(httpRequestFactory());
	}

	@Bean
	public ClientHttpRequestFactory httpRequestFactory() {
		log.info("初始化ClientHttpRequestFactory-开始");
		return new HttpComponentsClientHttpRequestFactory(httpClient());
	}

	@Bean
	public HttpClient httpClient() {
		log.info("初始化HttpClient-开始");

		Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
				.register("http", PlainConnectionSocketFactory.getSocketFactory())
				.register("https", SSLConnectionSocketFactory.getSocketFactory()).build();
		PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
		connectionManager.setMaxTotal(maxTotal); // 最大连接数
		connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute); // 单个路由最大连接数
		// connectionManager.setValidateAfterInactivity(validateAfterInactivity); // 最大空间时间

		RequestConfig requestConfig = RequestConfig.custom().setResponseTimeout(Timeout.ofMilliseconds(socketTimeout)) // 服务器返回数据(response)的时间，超过抛出read
																														// timeout
				// .setConnectTimeout(Timeout.ofMilliseconds(connectTimeout)) //
				// 连接上服务器(握手成功)的时间，超出抛出connect timeout
				.setConnectionRequestTimeout(Timeout.ofMilliseconds(connectionRequestTimeout))// 从连接池中获取连接的超时时间，超时间未拿到可用连接，会抛出org.apache.http.conn.ConnectionPoolTimeoutException:
				// Timeout waiting for connection from pool
				.build();

		// headers
		List<Header> headers = new ArrayList<>();
		headers.add(new BasicHeader("User-Agent",
				"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
		headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
		headers.add(new BasicHeader("Accept-Language", "zh-CN"));
		headers.add(new BasicHeader("Connection", "Keep-Alive"));
		headers.add(new BasicHeader("Content-type", "application/json;charset=UTF-8"));

		return HttpClients.custom().setDefaultRequestConfig(requestConfig).setConnectionManager(connectionManager)
				.setDefaultHeaders(headers)
				// 保持长连接配置，需要在头添加Keep-Alive
				.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
				// 重试次数，重试策略为最大次数3次，重试间隔为10秒
				.setRetryStrategy(new DefaultHttpRequestRetryStrategy(3, TimeValue.ofSeconds(10L))).build();
	}
}
